﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GKS.Extensions;
using System.Numerics;

namespace GKS {
    public static class Utilities {
        #region variables

        #endregion

        #region properties

        #endregion

        #region enums

        #endregion

        #region constructors

        #endregion

        #region methods
        public static Func<T, T, T> Sum<T>() {
            Func<T, T, T> ae = null;

            if (typeof(T) == typeof(byte)) {
                ae = ((left, right) => (left.CastTo<byte>() + right.CastTo<byte>()).CastTo<T>());
            } else if (typeof(T) == typeof(decimal)) {
                ae = ((left, right) => (left.CastTo<decimal>() + right.CastTo<decimal>()).CastTo<T>());
            } else if (typeof(T) == typeof(double)) {
                ae = ((left, right) => (left.CastTo<double>() + right.CastTo<double>()).CastTo<T>());
            } else if (typeof(T) == typeof(float)) {
                ae = ((left, right) => (left.CastTo<float>() + right.CastTo<float>()).CastTo<T>());
            } else if (typeof(T) == typeof(int)) {
                ae = ((left, right) => (left.CastTo<int>() + right.CastTo<int>()).CastTo<T>());
            } else if (typeof(T) == typeof(long)) {
                ae = ((left, right) => (left.CastTo<long>() + right.CastTo<long>()).CastTo<T>());
            } else if (typeof(T) == typeof(sbyte)) {
                ae = ((left, right) => (left.CastTo<sbyte>() + right.CastTo<sbyte>()).CastTo<T>());
            } else if (typeof(T) == typeof(short)) {
                ae = ((left, right) => (left.CastTo<short>() + right.CastTo<short>()).CastTo<T>());
            } else if (typeof(T) == typeof(uint)) {
                ae = ((left, right) => (left.CastTo<uint>() + right.CastTo<uint>()).CastTo<T>());
            } else if (typeof(T) == typeof(ulong)) {
                ae = ((left, right) => (left.CastTo<ulong>() + right.CastTo<ulong>()).CastTo<T>());
            } else if (typeof(T) == typeof(ushort)) {
                ae = ((left, right) => (left.CastTo<ushort>() + right.CastTo<ushort>()).CastTo<T>());
            } else if (typeof(T) == typeof(Complex)) {
                ae = ((left, right) => (left.CastTo<Complex>() + right.CastTo<Complex>()).CastTo<T>());
            } else if (typeof(T) == typeof(BigInteger)) {
                ae = ((left, right) => (left.CastTo<BigInteger>() + right.CastTo<BigInteger>()).CastTo<T>());
            }

            return ae;
        }

        public static Func<T, T, T> Multiplication<T>() {
            Func<T, T, T> me = null;

            if (typeof(T) == typeof(byte)) {
                me = ((left, right) => (left.CastTo<byte>() * right.CastTo<byte>()).CastTo<T>().CastTo<T>());
            } else if (typeof(T) == typeof(decimal)) {
                me = ((left, right) => (left.CastTo<decimal>() * right.CastTo<decimal>()).CastTo<T>());
            } else if (typeof(T) == typeof(double)) {
                me = ((left, right) => (left.CastTo<double>() * right.CastTo<double>()).CastTo<T>());
            } else if (typeof(T) == typeof(float)) {
                me = ((left, right) => (left.CastTo<float>() * right.CastTo<float>()).CastTo<T>());
            } else if (typeof(T) == typeof(int)) {
                me = ((left, right) => (left.CastTo<int>() * right.CastTo<int>()).CastTo<T>());
            } else if (typeof(T) == typeof(long)) {
                me = ((left, right) => (left.CastTo<long>() * right.CastTo<long>()).CastTo<T>());
            } else if (typeof(T) == typeof(sbyte)) {
                me = ((left, right) => (left.CastTo<sbyte>() * right.CastTo<sbyte>()).CastTo<T>());
            } else if (typeof(T) == typeof(short)) {
                me = ((left, right) => (left.CastTo<short>() * right.CastTo<short>()).CastTo<T>());
            } else if (typeof(T) == typeof(uint)) {
                me = ((left, right) => (left.CastTo<uint>() * right.CastTo<uint>()).CastTo<T>());
            } else if (typeof(T) == typeof(ulong)) {
                me = ((left, right) => (left.CastTo<ulong>() * right.CastTo<ulong>()).CastTo<T>());
            } else if (typeof(T) == typeof(ushort)) {
                me = ((left, right) => (left.CastTo<ushort>() * right.CastTo<ushort>()).CastTo<T>());
            } else if (typeof(T) == typeof(Complex)) {
                me = ((left, right) => (left.CastTo<Complex>() * right.CastTo<Complex>()).CastTo<T>());
            } else if (typeof(T) == typeof(BigInteger)) {
                me = ((left, right) => (left.CastTo<BigInteger>() * right.CastTo<BigInteger>()).CastTo<T>());
            }

            return me;
        }

        public static Func<T, T, T> Subtraction<T>() {
            Func<T, T, T> se = null;

            if (typeof(T) == typeof(byte)) {
                se = ((left, right) => (left.CastTo<byte>() - right.CastTo<byte>()).CastTo<T>());
            } else if (typeof(T) == typeof(decimal)) {
                se = ((left, right) => (left.CastTo<decimal>() - right.CastTo<decimal>()).CastTo<T>());
            } else if (typeof(T) == typeof(double)) {
                se = ((left, right) => (left.CastTo<double>() - right.CastTo<double>()).CastTo<T>());
            } else if (typeof(T) == typeof(float)) {
                se = ((left, right) => (left.CastTo<float>() - right.CastTo<float>()).CastTo<T>());
            } else if (typeof(T) == typeof(int)) {
                se = ((left, right) => (left.CastTo<int>() - right.CastTo<int>()).CastTo<T>());
            } else if (typeof(T) == typeof(long)) {
                se = ((left, right) => (left.CastTo<long>() - right.CastTo<long>()).CastTo<T>());
            } else if (typeof(T) == typeof(sbyte)) {
                se = ((left, right) => (left.CastTo<sbyte>() - right.CastTo<sbyte>()).CastTo<T>());
            } else if (typeof(T) == typeof(short)) {
                se = ((left, right) => (left.CastTo<short>() - right.CastTo<short>()).CastTo<T>());
            } else if (typeof(T) == typeof(uint)) {
                se = ((left, right) => (left.CastTo<uint>() - right.CastTo<uint>()).CastTo<T>());
            } else if (typeof(T) == typeof(ulong)) {
                se = ((left, right) => (left.CastTo<ulong>() - right.CastTo<ulong>()).CastTo<T>());
            } else if (typeof(T) == typeof(ushort)) {
                se = ((left, right) => (left.CastTo<ushort>() - right.CastTo<ushort>()).CastTo<T>());
            } else if (typeof(T) == typeof(Complex)) {
                se = ((left, right) => (left.CastTo<Complex>() - right.CastTo<Complex>()).CastTo<T>());
            } else if (typeof(T) == typeof(BigInteger)) {
                se = ((left, right) => (left.CastTo<BigInteger>() - right.CastTo<BigInteger>()).CastTo<T>());
            }

            return se;
        }

        public static Func<T, T, T> Division<T>() {
            Func<T, T, T> de = null;

            if (typeof(T) == typeof(byte)) {
                de = ((left, right) => (left.CastTo<byte>() / right.CastTo<byte>()).CastTo<T>());
            } else if (typeof(T) == typeof(decimal)) {
                de = ((left, right) => (left.CastTo<decimal>() / right.CastTo<decimal>()).CastTo<T>());
            } else if (typeof(T) == typeof(double)) {
                de = ((left, right) => (left.CastTo<double>() / right.CastTo<double>()).CastTo<T>());
            } else if (typeof(T) == typeof(float)) {
                de = ((left, right) => (left.CastTo<float>() / right.CastTo<float>()).CastTo<T>());
            } else if (typeof(T) == typeof(int)) {
                de = ((left, right) => (left.CastTo<int>() / right.CastTo<int>()).CastTo<T>());
            } else if (typeof(T) == typeof(long)) {
                de = ((left, right) => (left.CastTo<long>() / right.CastTo<long>()).CastTo<T>());
            } else if (typeof(T) == typeof(sbyte)) {
                de = ((left, right) => (left.CastTo<sbyte>() / right.CastTo<sbyte>()).CastTo<T>());
            } else if (typeof(T) == typeof(short)) {
                de = ((left, right) => (left.CastTo<short>() / right.CastTo<short>()).CastTo<T>());
            } else if (typeof(T) == typeof(uint)) {
                de = ((left, right) => (left.CastTo<uint>() / right.CastTo<uint>()).CastTo<T>());
            } else if (typeof(T) == typeof(ulong)) {
                de = ((left, right) => (left.CastTo<ulong>() / right.CastTo<ulong>()).CastTo<T>());
            } else if (typeof(T) == typeof(ushort)) {
                de = ((left, right) => (left.CastTo<ushort>() / right.CastTo<ushort>()).CastTo<T>());
            } else if (typeof(T) == typeof(Complex)) {
                de = ((left, right) => (left.CastTo<Complex>() / right.CastTo<Complex>()).CastTo<T>());
            } else if (typeof(T) == typeof(BigInteger)) {
                de = ((left, right) => (left.CastTo<BigInteger>() / right.CastTo<BigInteger>()).CastTo<T>());
            }

            return de;
        }

        public static Func<T, T, bool> GreaterThan<T>() {
            Func<T, T, bool> gte = null;

            if (typeof(T) == typeof(byte)) {
                gte = ((left, right) => ((left.CastTo<byte>() > right.CastTo<byte>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(decimal)) {
                gte = ((left, right) => ((left.CastTo<decimal>() > right.CastTo<decimal>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(double)) {
                gte = ((left, right) => ((left.CastTo<double>() > right.CastTo<double>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(float)) {
                gte = ((left, right) => ((left.CastTo<float>() > right.CastTo<float>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(int)) {
                gte = ((left, right) => ((left.CastTo<int>() > right.CastTo<int>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(long)) {
                gte = ((left, right) => ((left.CastTo<long>() > right.CastTo<long>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(sbyte)) {
                gte = ((left, right) => ((left.CastTo<sbyte>() > right.CastTo<sbyte>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(short)) {
                gte = ((left, right) => ((left.CastTo<short>() > right.CastTo<short>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(uint)) {
                gte = ((left, right) => ((left.CastTo<uint>() > right.CastTo<uint>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(ulong)) {
                gte = ((left, right) => ((left.CastTo<ulong>() > right.CastTo<ulong>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(ushort)) {
                gte = ((left, right) => ((left.CastTo<ushort>() > right.CastTo<ushort>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(BigInteger)) {
                gte = ((left, right) => ((left.CastTo<BigInteger>() > right.CastTo<BigInteger>()).CastTo<T>()).CastTo<bool>());
            }

            return gte;
        }

        public static Func<T, T, bool> SmallerThan<T>() {
            Func<T, T, bool> ste = null;

            if (typeof(T) == typeof(byte)) {
                ste = ((left, right) => ((left.CastTo<byte>() < right.CastTo<byte>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(decimal)) {
                ste = ((left, right) => ((left.CastTo<decimal>() < right.CastTo<decimal>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(double)) {
                ste = ((left, right) => ((left.CastTo<double>() < right.CastTo<double>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(float)) {
                ste = ((left, right) => ((left.CastTo<float>() < right.CastTo<float>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(int)) {
                ste = ((left, right) => ((left.CastTo<int>() < right.CastTo<int>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(long)) {
                ste = ((left, right) => ((left.CastTo<long>() < right.CastTo<long>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(sbyte)) {
                ste = ((left, right) => ((left.CastTo<sbyte>() < right.CastTo<sbyte>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(short)) {
                ste = ((left, right) => ((left.CastTo<short>() < right.CastTo<short>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(uint)) {
                ste = ((left, right) => ((left.CastTo<uint>() < right.CastTo<uint>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(ulong)) {
                ste = ((left, right) => ((left.CastTo<ulong>() < right.CastTo<ulong>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(ushort)) {
                ste = ((left, right) => ((left.CastTo<ushort>() < right.CastTo<ushort>()).CastTo<T>()).CastTo<bool>());
            } else if (typeof(T) == typeof(BigInteger)) {
                ste = ((left, right) => ((left.CastTo<BigInteger>() < right.CastTo<BigInteger>()).CastTo<T>()).CastTo<bool>());
            }

            return ste;
        }

        public static T MultiplicationId<T>() {
            T result = default(T);
            int id = 1;

            if (typeof(T) == typeof(byte) 
                || typeof(T) == typeof(decimal)
                || typeof(T) == typeof(double)
                || typeof(T) == typeof(float)
                || typeof(T) == typeof(int)
                || typeof(T) == typeof(long)
                || typeof(T) == typeof(sbyte)
                || typeof(T) == typeof(short)
                || typeof(T) == typeof(uint)
                || typeof(T) == typeof(ulong)
                || typeof(T) == typeof(ushort)
                || typeof(T) == typeof(Complex)
                || typeof(T) == typeof(BigInteger)) {
                result = id.CastTo<T>();
            }

            return result;
        }

        public static T SumId<T>() {
            T result = default(T);
            int id = 0;

            if (typeof(T) == typeof(byte)
                || typeof(T) == typeof(decimal)
                || typeof(T) == typeof(double)
                || typeof(T) == typeof(float)
                || typeof(T) == typeof(int)
                || typeof(T) == typeof(long)
                || typeof(T) == typeof(sbyte)
                || typeof(T) == typeof(short)
                || typeof(T) == typeof(uint)
                || typeof(T) == typeof(ulong)
                || typeof(T) == typeof(ushort)
                || typeof(T) == typeof(Complex)
                || typeof(T) == typeof(BigInteger)) {
                result = id.CastTo<T>();
            }

            return result;
        }
        #endregion
    }
}
